"""
Caching System
缓存系统 - 内存缓存和简单的缓存管理
"""

import asyncio
import time
from typing import Any, Optional, Dict, Callable, Union
from datetime import datetime, timedelta
from dataclasses import dataclass
import structlog
import json
import hashlib

# 配置结构化日志
logger = structlog.get_logger(__name__)


@dataclass
class CacheEntry:
    """缓存条目"""

    value: Any
    expiry: datetime
    access_count: int = 0
    last_access: datetime = None

    def __post_init__(self):
        if self.last_access is None:
            self.last_access = datetime.utcnow()


class SimpleMemoryCache:
    """简单的内存缓存实现"""

    def __init__(
        self,
        default_ttl: int = 300,  # 5分钟默认TTL
        max_size: int = 1000,  # 最大缓存条目数
        cleanup_interval: int = 60,  # 清理间隔（秒）
        enable_stats: bool = True,
    ):
        self.default_ttl = default_ttl
        self.max_size = max_size
        self.cleanup_interval = cleanup_interval
        self.enable_stats = enable_stats

        self._cache: Dict[str, CacheEntry] = {}
        self._lock = asyncio.Lock()
        self._stats = {"hits": 0, "misses": 0, "evictions": 0, "cleanups": 0}
        self._cleanup_task: Optional[asyncio.Task] = None
        self._is_running = False

    async def start(self) -> None:
        """启动缓存清理任务"""
        if self._is_running:
            return

        self._is_running = True
        self._cleanup_task = asyncio.create_task(self._periodic_cleanup())
        logger.info("缓存系统已启动", cleanup_interval=self.cleanup_interval)

    async def stop(self) -> None:
        """停止缓存清理任务"""
        if not self._is_running:
            return

        self._is_running = False
        if self._cleanup_task:
            self._cleanup_task.cancel()
            try:
                await self._cleanup_task
            except asyncio.CancelledError:
                pass

        logger.info("缓存系统已停止")

    async def get(self, key: str) -> Optional[Any]:
        """获取缓存值"""
        async with self._lock:
            entry = self._cache.get(key)

            if entry is None:
                if self.enable_stats:
                    self._stats["misses"] += 1
                return None

            # 检查是否过期
            if datetime.utcnow() >= entry.expiry:
                del self._cache[key]
                if self.enable_stats:
                    self._stats["misses"] += 1
                return None

            # 更新访问统计
            entry.access_count += 1
            entry.last_access = datetime.utcnow()

            if self.enable_stats:
                self._stats["hits"] += 1

            return entry.value

    async def set(self, key: str, value: Any, ttl: Optional[int] = None) -> None:
        """设置缓存值"""
        ttl = ttl or self.default_ttl
        expiry = datetime.utcnow() + timedelta(seconds=ttl)

        async with self._lock:
            # 检查是否需要清理空间
            if len(self._cache) >= self.max_size:
                await self._evict_lru()

            self._cache[key] = CacheEntry(value=value, expiry=expiry)

    async def delete(self, key: str) -> bool:
        """删除缓存项"""
        async with self._lock:
            if key in self._cache:
                del self._cache[key]
                return True
            return False

    async def clear(self) -> None:
        """清空缓存"""
        async with self._lock:
            self._cache.clear()
            logger.info("缓存已清空")

    async def exists(self, key: str) -> bool:
        """检查缓存项是否存在"""
        entry = await self.get(key)
        return entry is not None

    async def get_stats(self) -> Dict[str, Any]:
        """获取缓存统计信息"""
        async with self._lock:
            total_entries = len(self._cache)
            hit_rate = (
                self._stats["hits"] / (self._stats["hits"] + self._stats["misses"])
                if (self._stats["hits"] + self._stats["misses"]) > 0
                else 0
            )

            return {
                "total_entries": total_entries,
                "max_size": self.max_size,
                "hit_rate": round(hit_rate, 4),
                "stats": self._stats.copy(),
                "is_running": self._is_running,
            }

    async def _evict_lru(self) -> None:
        """LRU淘汰策略"""
        if not self._cache:
            return

        # 找到最少使用的条目
        lru_key = min(
            self._cache.keys(),
            key=lambda k: (self._cache[k].access_count, self._cache[k].last_access),
        )

        del self._cache[lru_key]
        if self.enable_stats:
            self._stats["evictions"] += 1

        logger.debug("LRU淘汰完成", evicted_key=lru_key)

    async def _periodic_cleanup(self) -> None:
        """定期清理过期缓存"""
        while self._is_running:
            try:
                await asyncio.sleep(self.cleanup_interval)
                await self._cleanup_expired()
            except asyncio.CancelledError:
                break
            except Exception as e:
                logger.error("缓存清理任务出错", error=str(e))

    async def _cleanup_expired(self) -> int:
        """清理过期缓存项"""
        now = datetime.utcnow()
        expired_keys = []

        async with self._lock:
            for key, entry in self._cache.items():
                if now >= entry.expiry:
                    expired_keys.append(key)

            for key in expired_keys:
                del self._cache[key]

            if self.enable_stats:
                self._stats["cleanups"] += 1

        if expired_keys:
            logger.debug("过期缓存清理完成", cleaned_count=len(expired_keys))

        return len(expired_keys)


class CacheManager:
    """缓存管理器 - 管理多个缓存实例"""

    def __init__(self):
        self.caches: Dict[str, SimpleMemoryCache] = {}
        self.default_cache: Optional[SimpleMemoryCache] = None

    def create_cache(
        self,
        name: str,
        default_ttl: int = 300,
        max_size: int = 1000,
        cleanup_interval: int = 60,
        enable_stats: bool = True,
    ) -> SimpleMemoryCache:
        """创建新的缓存实例"""
        if name in self.caches:
            raise ValueError(f"缓存 '{name}' 已存在")

        cache = SimpleMemoryCache(
            default_ttl=default_ttl,
            max_size=max_size,
            cleanup_interval=cleanup_interval,
            enable_stats=enable_stats,
        )

        self.caches[name] = cache

        if self.default_cache is None:
            self.default_cache = cache

        logger.info("缓存实例已创建", name=name, max_size=max_size, ttl=default_ttl)
        return cache

    def get_cache(self, name: str) -> Optional[SimpleMemoryCache]:
        """获取缓存实例"""
        return self.caches.get(name)

    def get_default_cache(self) -> SimpleMemoryCache:
        """获取默认缓存实例"""
        if self.default_cache is None:
            raise RuntimeError("默认缓存未初始化")
        return self.default_cache

    async def start_all(self) -> None:
        """启动所有缓存实例"""
        tasks = [cache.start() for cache in self.caches.values()]
        await asyncio.gather(*tasks)
        logger.info("所有缓存实例已启动", count=len(self.caches))

    async def stop_all(self) -> None:
        """停止所有缓存实例"""
        tasks = [cache.stop() for cache in self.caches.values()]
        await asyncio.gather(*tasks)
        logger.info("所有缓存实例已停止", count=len(self.caches))

    async def get_all_stats(self) -> Dict[str, Any]:
        """获取所有缓存的统计信息"""
        stats = {}
        for name, cache in self.caches.items():
            stats[name] = await cache.get_stats()
        return stats


# 全局缓存管理器实例
cache_manager = CacheManager()


def create_cache_key(*args, **kwargs) -> str:
    """创建缓存键"""
    # 将参数转换为可哈希的格式
    key_parts = []

    for arg in args:
        if isinstance(arg, (str, int, float, bool)):
            key_parts.append(str(arg))
        elif isinstance(arg, (list, dict)):
            key_parts.append(json.dumps(arg, sort_keys=True))
        else:
            key_parts.append(str(hash(arg)))

    for key, value in sorted(kwargs.items()):
        if isinstance(value, (str, int, float, bool)):
            key_parts.append(f"{key}={value}")
        elif isinstance(value, (list, dict)):
            key_parts.append(f"{key}={json.dumps(value, sort_keys=True)}")
        else:
            key_parts.append(f"{key}={hash(value)}")

    # 生成哈希键
    key_string = "|".join(key_parts)
    return hashlib.md5(key_string.encode()).hexdigest()


def cache_result(
    cache_name: str = "default", ttl: int = 300, key_func: Optional[Callable] = None
):
    """缓存装饰器"""

    def decorator(func: Callable) -> Callable:
        async def wrapper(*args, **kwargs):
            cache = (
                cache_manager.get_cache(cache_name) or cache_manager.get_default_cache()
            )

            # 生成缓存键
            if key_func:
                cache_key = key_func(*args, **kwargs)
            else:
                cache_key = create_cache_key(func.__name__, *args, **kwargs)

            # 尝试从缓存获取
            cached_result = await cache.get(cache_key)
            if cached_result is not None:
                logger.debug("缓存命中", func=func.__name__, key=cache_key)
                return cached_result

            # 执行函数并缓存结果
            logger.debug("缓存未命中", func=func.__name__, key=cache_key)
            result = await func(*args, **kwargs)
            await cache.set(cache_key, result, ttl=ttl)

            return result

        return wrapper

    return decorator


# 导出主要组件
__all__ = [
    "SimpleMemoryCache",
    "CacheManager",
    "cache_manager",
    "create_cache_key",
    "cache_result",
]
